﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace gChartSharp
{
    public class ShapeMarkerParam : ParamBase<ShapeMarker>, IRenderable
    {
        public override string Name { get { return "chm"; } }

        protected override char ParamSeparator { get { return '|'; } }
    }


    public class ShapeMarker : IRenderable
    {
        /// <summary>
        /// The type of marker.
        /// </summary>
        public MarkerType MarkerType { get; set; }


        /// <summary>
        /// An RRGGBB format hexadecimal number.
        /// </summary>
        public Color Color { get; set; }


        /// <summary>
        /// The index of the line on which to draw the marker. 
        /// This is 0 for the first data set, 1 for the second and so on. 
        /// </summary>
        public int DataSetIndex { get; set; }


        /// <summary>
        /// For all markers except a horizontal line, this is a floating point 
        /// value that specifies on which data point the marker will be drawn. 
        /// This can be: 0 for the first data point, 1 for the second and so on 
        /// or -1 to set for all data points. Specify a fraction to interpolate 
        /// a marker between two data points.
        /// </summary>
        public float DataPoint { get; set; }


        /// <summary>
        /// The size of the marker in pixels.
        /// </summary>
        public int Size { get; set; }


        /// <summary>
        /// Determines the order in which bars, lines, markers, and fills are drawn.
        /// </summary>
        public MarkerPriority Priority { get; set; }


        /// <summary>
        /// Only used if MarkerType is set to Text
        /// </summary>
        public string Text { get; set; }


        /// <summary>
        /// This constructor should only be used if MarkerType is set to Text
        /// </summary>
        /// <param name="markerType"></param>
        /// <param name="color"></param>
        /// <param name="dataSetIndex"></param>
        /// <param name="dataPoint"></param>
        /// <param name="size"></param>
        /// <param name="priority"></param>
        /// <param name="text"></param>
        public ShapeMarker(MarkerType markerType, Color color, int dataSetIndex, float dataPoint, int size, MarkerPriority priority, string text)
        {
            MarkerType = markerType;
            Color = color;
            DataSetIndex = dataSetIndex;
            DataPoint = dataPoint;
            Size = size;
            Priority = priority;
            Text = text;
        }

        public ShapeMarker(MarkerType markerType, Color color, int dataSetIndex, float dataPoint, int size)
            : this(markerType, color, dataSetIndex, dataPoint, size, MarkerPriority.Normal, null) { }

        public ShapeMarker(MarkerType markerType, Color color, int dataSetIndex, float dataPoint, int size, string text)
            : this(markerType, color, dataSetIndex, dataPoint, size, MarkerPriority.Normal, text) { }

        public ShapeMarker(MarkerType markerType, Color color, int dataSetIndex, float dataPoint, int size, MarkerPriority priority)
            : this(markerType, color, dataSetIndex, dataPoint, size, priority, null) { }


        public string Render()
        {
            // Special rendering if marker type is text
            if (MarkerType == MarkerType.Text)
            {
                if (String.IsNullOrEmpty(Text))
                    throw new ParamException("MarkerType is set to Text but no text is supplied.");

                return String.Format("{0}{1},{2},{3},{4},{5},{6}", (char)MarkerType,
                    Text.Replace(' ', '+').Replace("\n", "|"),
                    Color.ToHtml(), DataSetIndex,
                    DataPoint, Size, (int)Priority);
            }
            else
            {
                return String.Format("{0},{1},{2},{3},{4},{5}", (char)MarkerType,
                    Color.ToHtml(), DataSetIndex,
                    DataPoint, Size, (int)Priority);
            }
        }
    }


    public enum MarkerType
    {
        /// <summary>
        /// Arrow
        /// </summary>
        Arrow = 'a',

        /// <summary>
        /// Cross
        /// </summary>
        Cross = 'c',

        /// <summary>
        /// Diamond
        /// </summary>
        Diamond = 'd',

        /// <summary>
        /// Circle
        /// </summary>
        Circle = 'o',

        /// <summary>
        /// Square
        /// </summary>
        Square = 's',

        /// <summary>
        /// Text
        /// </summary>
        Text = 't',

        /// <summary>
        /// A vertical line from the x-axis to the data point.
        /// </summary>
        VerticalLineFromXAxisToDataPoint = 'v',

        /// <summary>
        /// A vertical line to the top of the chart.
        /// </summary>
        VerticalLine = 'V',

        /// <summary>
        /// A horizontal line across the chart.
        /// </summary>
        HorizontalLine = 'h',

        /// <summary>
        /// An X shape.
        /// </summary>
        XShape = 'x'
    }


    /// <summary>
    /// Determines the order in which bars, lines, markers, and fills are drawn.
    /// </summary>
    public enum MarkerPriority
    {
        /// <summary>
        /// -1 specifies the marker is drawn before all other parts of the chart. 
        /// This means the marker will be hidden if another chart element is drawn 
        /// in the same place.
        /// </summary>
        AlwaysBehind = -1,

        /// <summary>
        /// 0 is the default and specifies the marker is drawn on top of bars or 
        /// lines and beneath other markers.
        /// </summary>
        Normal = 0,

        /// <summary>
        /// 1 specifies the marker is drawn on top of all other parts of the chart. 
        /// This means it will hide another chart element if it is drawn in the same place.
        /// </summary>
        AlwaysOnTop = 1
    }
}
